﻿using Newtonsoft.Json.Linq;
using Pay.Core;
using Pay.TO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace Pay.Token {
    public class AppAuthorizeAttribute : AuthorizeAttribute {
        public string[] Roles { get; set; }

        public AppAuthorizeAttribute() { }
        public AppAuthorizeAttribute(params string[] roles) { Roles = roles; }

        protected override bool AuthorizeCore(HttpContextBase httpContext) {
            if (httpContext == null)
                throw new ArgumentNullException("HttpContext");
            if (!httpContext.User.Identity.IsAuthenticated || Roles == null || Roles.Length == 0) {
                httpContext.Response.StatusCode = 401;
                return false;
            }
            if (Roles.Any(httpContext.User.IsInRole))
                return true;
            return false;
        }

        public override void OnAuthorization(AuthorizationContext filterContext) {
            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = filterContext.ActionDescriptor.ActionName;
            HttpContext context = HttpContext.Current;
            if (context.Request.Headers["Authorization"] != null) {
                var log = IocHelper.Get<ILogHelper>("ui_error");
                var authorization = context.Request.Headers["Authorization"];
                var formsCookie = new FormsCookie();
                AuthenticationHeaderValue authHeaderVal = AuthenticationHeaderValue.Parse(authorization);
                string decodedJwt = formsCookie.ValidateToken(authHeaderVal.Parameter);
                if (!string.IsNullOrEmpty(decodedJwt)) {
                    dynamic root = JObject.Parse(decodedJwt);
                    string user_id = root.merchant_id;
                    string username = root.iss;
                    var userCookie = new userCookie { user_id = long.Parse(user_id), roles = new List<string> { "Member", "TokenMemeber" } };
                    formsCookie.FormsCookieSave(username, userCookie, true);
                    var claims = new List<Claim>{
                        new Claim(ClaimTypes.NameIdentifier, user_id),
                        new Claim(ClaimTypes.Name, username),
                        new Claim(ClaimTypes.AuthenticationMethod, "Password"),
                        new Claim(ClaimTypes.UserData, userCookie.ToJson())
                    };
                    foreach (var role in userCookie.roles)
                        claims.Add(new Claim(ClaimTypes.Role, role));
                    ClaimsPrincipal principal = new ClaimsPrincipal(new[] { new ClaimsIdentity(claims, "Bearer") });
                    Thread.CurrentPrincipal = principal;
                    context.User = principal;
                    base.OnAuthorization(filterContext);
                }
            } else {
                if (context.User != null && context.User.Identity.IsAuthenticated) {
                    FormsIdentity _Identity = (FormsIdentity)context.User.Identity;
                    var userCookie = _Identity.Ticket.UserData.ToObject<userCookie>();
                    //_Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userCookie.user_id.ToString()));
                    //var roles = userCookie.roles.ToArray();
                    //var principal = new GenericPrincipal(_Identity, roles);
                    //Thread.CurrentPrincipal = principal;
                    //context.User = principal;
                    var claims = new List<Claim>{
                        new Claim(ClaimTypes.NameIdentifier, userCookie.user_id.ToString()),
                        new Claim(ClaimTypes.Name, context.User.Identity.Name),
                        new Claim(ClaimTypes.AuthenticationMethod, "Password"),
                        new Claim(ClaimTypes.UserData, userCookie.ToJson())
                    };
                    foreach (var role in userCookie.roles)
                        claims.Add(new Claim(ClaimTypes.Role, role));
                    ClaimsPrincipal principal = new ClaimsPrincipal(new[] { new ClaimsIdentity(claims, "Bearer") });
                    Thread.CurrentPrincipal = principal;
                    context.User = principal;
                    base.OnAuthorization(filterContext);
                } else if (!filterContext.HttpContext.User.Identity.IsAuthenticated
                  && (!filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any()
                      && filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AuthorizeAttribute), true).Any())) {
                    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
                    if (filterContext.HttpContext.Request.IsAjaxRequest()) {
                        filterContext.HttpContext.SkipAuthorization = true;
                        filterContext.HttpContext.Response.Clear();
                        //filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                        var jsonResult = new JsonResult();
                        jsonResult.Data = new ResultMessage<object>((int)System.Net.HttpStatusCode.Unauthorized, "您还未登录，无法操作！");
                        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                        jsonResult.ContentType = "application/json";
                        filterContext.Result = jsonResult;
                        filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext);
                        filterContext.HttpContext.Response.End();
                    } else {
                        filterContext.HttpContext.SkipAuthorization = true;
                        filterContext.HttpContext.Response.Clear();
                        //filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                        //HandleErrorInfo data = new HandleErrorInfo(new Exception("您还未登录，无法操作！"), (string)filterContext.RouteData.Values["controller"], (string)filterContext.RouteData.Values["action"]);
                        //filterContext.Controller.ViewData.Model = data;
                        //filterContext.Result = new ViewResult { ViewName = "Error", ViewData = filterContext.Controller.ViewData };
                        if (Roles.Contains("TokenMemeber"))
                            filterContext.Result = new RedirectResult("/h5/coin/login?ReturnUrl=" + WebHelper.GetUrlReferrer());
                        else
                            filterContext.Result = new RedirectResult(FormsAuthentication.LoginUrl + "?ReturnUrl=" + System.Web.HttpUtility.UrlEncode(WebHelper.GetUrl()));
                    }
                }
            }
        }
    }
}